import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map.Entry;

class UDPServer extends UDPClient{ 	

	UDPServer(int portNum, String username){
		super(portNum, username);
		String myKey = "IP:"+this.getLocalIpAddress()+":PORT:"+this.getLocalPortNum();
		this.memberList.put(myKey, new UDPNode(userName, this.getLocalInetAddress(), this.localPortNum, true));
		System.out.println ("Group built up.");	
		
	}
	
	UDPServer(UDPClient client){
		/* build up a UDPServer */
		super(client.getLocalPortNum(), client.getUserName(), client.getUDPSocket(), client.getMemberList());
		String myKey = "IP:"+this.getLocalIpAddress()+":PORT:"+this.getLocalPortNum();
		/* upgrade this client's ISLEADER to be true*/
		this.memberList.put(myKey, new UDPNode(this.userName,this.getLocalInetAddress(),this.getLocalPortNum(),true));
	}

	/**
	 * perform regular aliveness check to everyone in this chat group
	 * @throws InterruptedException when Thread.sleep() throws exception
	 */
	public void aliveCheck(){		
		String checkMsg="Alive?";		
		while(true){			
			if(this.memberList.size()>1){//if there is any other member in group
				for(UDPNode member : this.memberList.values()){
					if(!member.isLeader()){
						/*subtract every member's aliveTry by 1*/
						member.decreaseAlive();
						System.out.println(member.getUsername()+" aliveTry----"+member.getAliveTry());
						/*ask everyone if alive*/
						try {
							System.out.println("checking"+member.getUsername());
							this.getUDPSocket().send(new DatagramPacket(checkMsg.getBytes(), checkMsg.length(), member.getIpAddress(), member.getPortNum()));
						} catch (IOException e) {
							System.out.println("Oops, CheckMsg sending failed!");
							e.printStackTrace();
						}
					}
				}
			}
			try {
				Thread.sleep(this.TIME);
			} catch (InterruptedException e) {
				System.out.println("Oops, something bad happened when thread sleep");
				e.printStackTrace();
			}	
			/*check through memberList for anyone died, remove this member, broadcast latest memberList if changed*/
			HashMap<String, UDPNode> latestList = new HashMap<String, UDPNode>();
			latestList.putAll(this.memberList);
			for(Entry<String, UDPNode> entry : latestList.entrySet()){
				if(entry.getValue().getAliveTry()<0){
					broadcastMessage(entry.getValue().getUsername()+" just left...");
					this.memberList.remove(entry.getKey());
				}
			}
			if(!this.memberList.equals(latestList)){
				System.out.println("Someone left my group, sending new memberList to the rest...");
				broadcastMessage(memberListToString());	
			}
		}
	}

	/**
	 * Send message to all member in current memberList
	 * @param msgToSend message of any content sent by leader to all clients in group
	 */
	public void broadcastMessage(String msgToSend){	
		System.out.println("BROADCAST----"+msgToSend);
		for(UDPNode member : this.memberList.values()){
			if(!member.isLeader()){
				try {
					this.getUDPSocket().send(new DatagramPacket(msgToSend.getBytes(), msgToSend.length(), member.getIpAddress(), member.getPortNum()));
				} catch (IOException e) {
					System.out.println("Oops, Package send failed!");
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * @return a String representing leader's memberList content
	 */
	public String memberListToString(){
		String allMemberInfo = "";				
		for(UDPNode member : this.memberList.values()){
			allMemberInfo += member.toString();
		};
		return allMemberInfo;
	}
	@Override
	public void reportAlive(){
		throw new UnsupportedOperationException();
	}
	
	@Override
	public void checkServerAlive(){
		throw new UnsupportedOperationException();
	}
	
	@Override
	public InetAddress getServerAddr(){
		throw new UnsupportedOperationException();
	}

	@Override
	public int getServerPortNum(){
		throw new UnsupportedOperationException();
	}

}  
